#ifndef ASYNC_LOGGER_H
#define ASYNC_LOGGER_H
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <thread>
#include <chrono>
#include <iomanip>
#include <functional>
#include <string>
#include <filesystem>
// const char* project_root = PROJECT_ROOT_PATH;  // 直接获取根目录路径
// const char* outputDir = project_root+"./logs/";

enum class LogLevel {
    INFO,
    WARNING,
    ERROR,
    DEBUG
};

struct LogMessage {
    LogLevel level;
    std::string message;
    std::chrono::system_clock::time_point timestamp;

    // 普通构造函数
    LogMessage(LogLevel l, const std::string& msg, std::chrono::system_clock::time_point ts)
        : level(l), message(msg), timestamp(ts) {
    }

    // 移动构造函数
    LogMessage(LogLevel l, std::string&& msg, std::chrono::system_clock::time_point ts)
        : level(l), message(std::move(msg)), timestamp(ts) {
    }

    // 默认的拷贝构造函数和赋值操作符
    LogMessage(const LogMessage&) = default;
    LogMessage& operator=(const LogMessage&) = default;

    // 默认的移动构造函数和赋值操作符
    LogMessage(LogMessage&&) = default;
    LogMessage& operator=(LogMessage&&) = default;
};

class Logger {
public:
    static Logger& instance() {
        static Logger instance;
        return instance;
    }
    //noncopyable
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    void log(LogLevel level, const std::string& message, const char* file, int line) {
        {
            std::lock_guard<std::mutex> lock(cur_buffer_mutex_);
            currentBuffer_.emplace_back(LogMessage{
                level,
                "[" + std::string(file) + ":" + std::to_string(line) + "] " +
                "[Thread " + std::to_string(std::hash<std::thread::id>{}(std::this_thread::get_id())) + "] " +
                message,
                std::chrono::system_clock::now()
                });

            if (currentBuffer_.size() >= bufferSize_) {
                std::lock_guard<std::mutex> lock(swap_mutex_);
                currentBuffer_.swap(nextBuffer_);
                cond_.notify_one(); // 通知后台线程处理日志
            }
        }
    }
private:
    Logger() : running_(false) {
        // 输出项目根路径
#ifdef PROJECT_ROOT_PATH
        std::cout << "Root: " << PROJECT_ROOT_PATH << std::endl; 
        outputFile_ = std::string(PROJECT_ROOT_PATH) + "/app.log";
#else
        std::cout << "Root: " << "unknown" << std::endl; 
        outputFile_ = "app.log";
#endif
        std::cout<<"log output file: "<<outputFile_<<std::endl;
        start();
    }

    ~Logger() {
        stop();
        std::cout << "~Logger()" << std::endl;
    }

    void start() {
        static std::once_flag flag;
        std::call_once(flag, [this] {
            running_.store(true);
            thread_ = std::thread(&Logger::processLogs, this);
            });
    }

    void stop() {
        {
            running_.store(false);
            cond_.notify_one(); // 通知后台线程处理日志
        }

        if (thread_.joinable()) {
            thread_.join();
        }
        flush(); // 清空currentBuffer_剩余的日志
    }

    // 日志处理线程主循环，关闭（running_置为false）后，会将nextBuffer_中的日志写入文件
    void processLogs() {
        while (running_ || !nextBuffer_.empty()) {
            std::vector<LogMessage> bufferToWrite;
            {
                std::unique_lock<std::mutex> lock(swap_mutex_);
                cond_.wait(lock, [this] { return !nextBuffer_.empty() || !running_; });
                if (!running_ && nextBuffer_.empty()) return;//只有当日志组件关闭 且 nextBuffer_没有日志时才返回
                if (!nextBuffer_.empty()) {
                    bufferToWrite.swap(nextBuffer_);
                }
            }
            if (!bufferToWrite.empty()) {
                writeToDisk(bufferToWrite);
            }
        }
    }

    void writeToDisk(const std::vector<LogMessage>& buffer) {
        std::ofstream outfile(outputFile_, std::ios::app);
        for (const auto& msg : buffer) {
            auto time = std::chrono::system_clock::to_time_t(msg.timestamp);
            std::tm tm_buf;
            // 使用线程安全的localtime_r
            localtime_r(&time, &tm_buf);

            outfile << "[" << getLogLevelString(msg.level) << "] "
                << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S")
                << " " << msg.message;
        }
    }

    void flush() {
        std::lock_guard<std::mutex> lock(cur_buffer_mutex_);
        if (!currentBuffer_.empty()) {
            writeToDisk(currentBuffer_);
            currentBuffer_.clear();
        }
    }

    std::string getLogLevelString(LogLevel level) {
        switch (level) {
        case LogLevel::INFO:    return "INFO";
        case LogLevel::WARNING: return "WARNING";
        case LogLevel::ERROR:   return "ERROR";
        case LogLevel::DEBUG:   return "DEBUG";
        default:                return "UNKNOWN";
        }
    }

    std::string outputFile_;
    const size_t bufferSize_ = 256;
    std::atomic<bool> running_;
    std::thread thread_;
    std::vector<LogMessage> currentBuffer_;
    std::vector<LogMessage> nextBuffer_;
    std::mutex cur_buffer_mutex_;                // 用于保护currentBuffer_的写入，size检查与交换
    std::mutex swap_mutex_;                      // 用于保护缓冲区交换
    std::condition_variable cond_;               // 用于写日志的线程与日志组件后台线程的通信
};

class LogStream {
public:
    LogStream(Logger& logger, LogLevel level)
        : logger_(logger), level_(level), buffer_() {
    }

    LogStream(Logger& logger, LogLevel level, const char* file, int line)
        : logger_(logger), level_(level), buffer_(), file_(file), line_(line) {
    }

    ~LogStream() {
        if (!buffer_.str().empty()) {
            logger_.log(level_, buffer_.str() + '\n', file_, line_);
        }
    }

    template <typename T>
    LogStream& operator<<(const T& msg) {
        buffer_ << msg;
        return *this;
    }

    LogStream& operator<<(std::ostream& (*pf)(std::ostream&)) {
        buffer_ << pf;
        return *this;
    }

private:
    Logger& logger_;
    LogLevel level_;
    std::ostringstream buffer_;
    const char* file_;
    int line_;
};
#define LOG_LV(level) LogStream(Logger::instance(), LogLevel::level, __FILE__, __LINE__)
// #define LOG_LV(level) LogStream(Logger::instance(), LogLevel::level)
#undef LOG
#define LOG LOG_LV(INFO)
#define LOGW LOG_LV(WARNING)
#define LOGE LOG_LV(ERROR)
#define LOGD LOG_LV(DEBUG)

#undef LOG
#define LOG while (false) LogStream(Logger::instance(), LogLevel::INFO, __FILE__, __LINE__)

#endif // ASYNC_LOGGER_H